package battleship.view;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;

import battleship.Controller;
import battleship.Loop;
import battleship.PluginAI;
import battleship.PluginLoop;
import battleship.PluginSetup;
import battleship.Setup;
import battleship.data.SaveLoader;
import battleship.data.SaveXML;
import battleship.field.Field;
import battleship.player.Player;
import battleship.view.fieldpainters.FieldPainterLoop;
import battleship.view.fieldpainters.FieldPainterSetup;

@SuppressWarnings("serial")
public class GUI extends JFrame{
	
	private SetupFieldGui setupFieldSize;
	
	private SetupGui setupPlayers;
	private JButton confirmSetupPlayers;
	private JButton confirmSetupBoats;
	private JButton repeatSetupBoats;
	
	private JPanel confirmRepeatButtons;
	
	private FieldPainterSetup[] setupBoatsFieldView;
	
	private JLabel[] notificationArea;
	
	private FieldPainterLoop[] loopBoatsFieldView;
	
	private JPanel[] fieldPanel;
	
	private JScrollPane[] fieldContainer;
	
	private int currentPlayer;
	
	//loop field panel
	private JPanel dualFieldView;
	
	//loop info panel items
	private JPanel loopInfo;
	
	private JLabel[] loopPlayerName;
	private JLabel[] playerHits;
	
	private JPanel progressPanel;
	private JLabel winProgessLabel;
	private JProgressBar winProgress;
	
	/* menu options */
	
	private JMenuBar menu;
	
	private JMenu file;
	private JMenuItem quit;
	
	private JMenu setup;
	private JMenuItem[] setupItems;
	
	private JMenu loop;
	private JMenuItem[] loopItems;
	
	private JMenu help;
	private JMenuItem rules;
	private JMenuItem about;
	
	private JButton loadSave;
	
	public GUI()
	{
		this.setTitle("Zeeslag");
		makeComponents();
		addLayout();
		addMenuBar();
		addHelpMenu();
		addListeners();
		makeVisible();
	}
	
	public void setNotificationText(String notification, boolean important)
	{	
		if(Setup.getState() == Setup.SETUP)
		{
			setupBoatsFieldView[currentPlayer].setNotificationText(notification, important);
		}
		else if(Setup.getState() == Setup.LOOP)
		{
			loopBoatsFieldView[currentPlayer].setNotificationText(notification, important);
		}

	}

	public void makeComponents()
	{

		notificationArea = new JLabel[] { new JLabel("speler 1"), new JLabel("speler 2")};

		menu = new JMenuBar();
		file = new JMenu("File");
		file.setMnemonic(KeyEvent.VK_F);
		quit = new JMenuItem("Quit");
		quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
		menu.add(file);
		file.add(quit);
		
		setupFieldSize = new SetupFieldGui();
		
		loadSave = new JButton("laad savefile");
		
		setupPlayers = new SetupGui();
		
		confirmSetupPlayers = new JButton("Confirm Setup");
		
		try {
			Setup.SAVER = new SaveXML();
			Setup.LOADER = new SaveLoader();
			
			
		} catch (Exception e) {
			loadSave.setText("corrupted save");
			loadSave.setEnabled(false);
			SaveXML.FILE.delete();
		} 
		
		checkSaveFile();
		
		Setup.loadEndPlugins();
		
		
	}
	
	public void addLayout()
	{
		
		// setup phase
		this.setLayout(new BorderLayout());
		
		this.add(setupFieldSize, BorderLayout.CENTER);
		this.add(setupPlayers, BorderLayout.SOUTH);
		
		//this.add(containSave, BorderLayout.EAST);
		
		setupFieldSize.getSpinnerGroup().add(confirmSetupPlayers);
		setupFieldSize.getSpinnerGroup().add(loadSave);	
	}
	
	public void makeVisible()
	{
		this.pack();
		this.setLocation(300, 300);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
	}
	
	public void addListeners()
	{
		confirmSetupPlayers.addActionListener(new ConfirmSetupPlayers());
		loadSave.addActionListener(new LoadListener());
	}
	
	public JMenu getFileMenu()
	{
		return file;
	}
	
	public void checkSaveFile()
	{
		if(!Setup.LOADER.LoadField())
		{
			loadSave.setEnabled(false);
			loadSave.setText("geen save gevonden");
		}
	}
	
	public void displayError(String error,PluginLoop plugin) {
		//error's are differently implemented
	}

	public void displayNotification(String note) {
		//notifications are differently implemented
		
	}

	public void displayHeader(String header) {
		//headers are not implementable
	}
	
	public void stateChangeSetup()
	{
		Setup.setState(Setup.SETUP);
		Setup.loadSetupPlugins();
		addSetupMenu();
		
		removeSetupPlayers();
		
		setupBoatsFieldView[0].fetchBoats();
		setupBoatsFieldView[1].fetchBoats();
		
		setupBoatsFieldView[0].repaint();
		setupBoatsFieldView[1].repaint();
		
		this.add(fieldContainer[currentPlayer]);
		this.pack();
	}
	
	public void removeSetupPlayers()
	{
		this.remove(setupFieldSize);
		this.remove(setupPlayers);
	}
	
	public void addSetupMenu()
	{
		setup = new JMenu("Setup");
		setup.setMnemonic(KeyEvent.VK_S);
		setupItems = new JMenuItem[Controller.getPluginsSetup().size()];
		for(int plugin = 0; plugin < Controller.getPluginsSetup().size(); plugin++)
		{
			setupItems[plugin] = new JMenuItem(
					Controller.getPluginsSetup().get(plugin).setupGetFunction());
			setup.add(setupItems[plugin]);
			setupItems[plugin].addActionListener(new SetupItemsListener(
					Controller.getPluginsSetup().get(plugin).setupGetFunction()));
		}
		
		if(setupItems.length != 0)
		{
			menu.add(setup);
		}
	}
	
	class SetupItemsListener implements ActionListener
	{

		String name;
		
		public SetupItemsListener(String name)
		{
			this.name = name;
		}
		@Override
		public void actionPerformed(ActionEvent e) 
		{
			for(PluginSetup plugin : Controller.getPluginsSetup())
			{
				if (plugin.setupGetFunction().equals(name))
				{
					for(int boat = 0; boat < Setup.getPlayers()[currentPlayer].getField().getBoats().length; ++boat)
					{
						if (!Setup.getPlayers()[currentPlayer].getField().getBoats()[boat].getSetup())
						{
							plugin.setupExecFunction(
									Setup.getPlayers()[currentPlayer],
									Setup.getPlayers()[currentPlayer].getField().getBoats()[boat],
									null);
						}
					}
				}
			}
			repaint();
		}
	}
	
	class LoopItemsListener implements ActionListener
	{

		private String name;
		
		public LoopItemsListener(String name)
		{
			this.name = name;
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			for(PluginLoop plug : Controller.getPluginsLoop())
			{
				if(plug.loopGetFunction().equals(name))
				{
					plug.loopExecFunction(null, Setup.getPlayer2(Loop.getLastTurn())); 
					//player variable not yet used by any of the functions available atm
				}
			}
		}
	}
	
	public void stateChangeSaveLoaded()
	{
		loadFieldPanels();
		Setup.setState(Setup.LOOP);
		
		removeSetupPlayers();
		loadLoop();
		
		for(int player = 0; player < Setup.getPlayers().length; ++player)
		{
			loopBoatsFieldView[player].updateHits();
			loopBoatsFieldView[player].updateProgressBar();
		}
	}
	
	public void addLoopMenu()
	{
		loop = new JMenu("Game");
		loop.setMnemonic(KeyEvent.VK_G);
		
		loopItems = new JMenuItem[Controller.getPluginsLoop().size()];
		for(int plugin = 0; plugin < Controller.getPluginsLoop().size(); plugin++)
		{
			loopItems[plugin] = new JMenuItem(
					Controller.getPluginsLoop().get(plugin).loopGetFunction());
			loop.add(loopItems[plugin]);
			loopItems[plugin].addActionListener(new LoopItemsListener(
					Controller.getPluginsLoop().get(plugin).loopGetFunction()));
		}
		
		if(loopItems.length != 0)
		{
			menu.add(loop);
		}
	}
	
	class ConfirmSetupPlayers implements ActionListener
	{

		@Override
		public void actionPerformed(ActionEvent e) {
			String player1name = setupPlayers.getNamePlayer1();
			String player2name = setupPlayers.getNamePlayer2();
			
			boolean player1bot = setupPlayers.getBotPlayer1();
			boolean player2bot = setupPlayers.getBotPlayer2();
			
			PluginAI player1ai = setupPlayers.getAIPlayer1();
			PluginAI player2ai = setupPlayers.getAIPlayer2();
			
			int x = setupFieldSize.getXField();
			int y = setupFieldSize.getYField();
			
			confirmSetupBoats = new JButton("doorgaan");
			repeatSetupBoats = new JButton("opnieuw");
			
			confirmRepeatButtons = new JPanel(new FlowLayout());
			confirmRepeatButtons.add(confirmSetupBoats);
			confirmRepeatButtons.add(repeatSetupBoats);
			
			Setup.getPlayers()[0] = new Player(player1name, player1bot);
			Setup.getPlayers()[1] = new Player(player2name, player2bot);
			
			Setup.getPlayers()[0].setAI(player1ai);
			Setup.getPlayers()[1].setAI(player2ai);
			
			currentPlayer = 0;
			
			setupBoatsFieldView = new FieldPainterSetup[] { 
					new FieldPainterSetup(Setup.getPlayers()[0], notificationArea[0]),
					new FieldPainterSetup(Setup.getPlayers()[1], notificationArea[1])
			};
			
			loadFieldPanels();
			
			fieldPanel[0].add(
					setupBoatsFieldView[0],
					BorderLayout.NORTH);
			fieldPanel[1].add(
					setupBoatsFieldView[1],
					BorderLayout.NORTH);
			
			loadFieldContainers();
			
			add(confirmRepeatButtons, BorderLayout.SOUTH);
			
			repeatSetupBoats.addActionListener(new ResetField());
			confirmSetupBoats.addActionListener(new ResetField());
			
			Field.setHeight(y);
			Field.setWidth(x);
			
			stateChangeSetup();
		}
		
	}
	
	public void loadFieldPanels()
	{
		fieldPanel = new JPanel[] { 
				new JPanel(new BorderLayout()),
				new JPanel(new BorderLayout())
		};
		
		
		
		fieldPanel[0].add(
				notificationArea[0],
				BorderLayout.CENTER);
		fieldPanel[1].add(
				notificationArea[1],
				BorderLayout.CENTER);
	}
	
	public void loadFieldContainers()
	{
		fieldContainer = new JScrollPane[] {
				new JScrollPane(fieldPanel[0]),
				new JScrollPane(fieldPanel[1])
		};
	}
	
	public void addMenuBar()
	{
		this.setJMenuBar(menu);
		quit.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
				
			}
		});
	}
	
	class ResetField implements ActionListener
	{

		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getSource().equals(confirmSetupBoats))
			{
				// checks if all boats are set up
				if (!Setup.getPlayers()[currentPlayer].getField().getBoatsSet(false))
				{
					setNotificationText("Nog niet alle boten zijn ingesteld", true);
				}
				else if(currentPlayer == 0)
				{

					//adds player2's field and removes old one

					remove(fieldContainer[currentPlayer]);

					currentPlayer = 1;

					add(fieldContainer[currentPlayer]);

				}
				else
				{
					stateChangeLoop();
				}
			}
			else if (e.getSource().equals(repeatSetupBoats))
			{

				int x = Field.getWidth();
				int y = Field.getHeight();

				Setup.getPlayers()[currentPlayer].setField(new Field());
				Field.setHeight(y);
				Field.setWidth(x);
				
				setupBoatsFieldView[currentPlayer].resetLastPointClicked();
				setupBoatsFieldView[currentPlayer].fetchBoats();
				setupBoatsFieldView[currentPlayer].repaint();
				setupBoatsFieldView[currentPlayer].setFinished(false);
			}
			validate();
			repaint();
		}
		
	}

	public void stateChangeLoop() {
		
		//field view items
		this.remove(fieldContainer[currentPlayer]);
		this.remove(confirmRepeatButtons);
		fieldPanel[currentPlayer].remove(
				setupBoatsFieldView[currentPlayer]);
		
		fieldPanel[(currentPlayer + 1) % 2].remove(
				setupBoatsFieldView[(currentPlayer + 1) % 2]);
		
		loadLoop();
		menu.remove(setup);
	}
	
	class LoadListener implements ActionListener
	{

		@Override
		public void actionPerformed(ActionEvent e) {
			
			Setup.LOADER.injectData();
			stateChangeSaveLoaded();
		}
		
	}
	
	public void loadLoop()
	{
		loadFieldContainers();
		
		currentPlayer = 0;

		dualFieldView = new JPanel(new GridLayout(1, 2, 10, 10));



		dualFieldView.add(fieldContainer[(currentPlayer + 1) % 2]);
		dualFieldView.add(fieldContainer[currentPlayer]);

		this.add(dualFieldView,BorderLayout.NORTH);
		this.repaint();

		Setup.setState(Setup.LOOP);
		Setup.loadLoopPlugins();

		addLoopMenu();

		//field info items

		loopInfo = new JPanel(new GridLayout(2, 3));

		loopPlayerName = new JLabel[] { 
				new JLabel(Setup.getPlayers()[0].getName(), JLabel.LEFT),
				new JLabel(Setup.getPlayers()[1].getName(), JLabel.RIGHT)
		};
		playerHits = new JLabel[] {
				new JLabel("0", JLabel.LEFT),
				new JLabel("0", JLabel.RIGHT)
		};

		progressPanel = new JPanel(new GridLayout(2, 1));
		winProgessLabel = new JLabel("spel vooruitgang", JLabel.CENTER);
		winProgress = new JProgressBar();
		progressPanel.add(winProgessLabel);
		progressPanel.add(winProgress);
		
		loopInfo.add(loopPlayerName[0]);
		loopInfo.add(new JPanel());
		loopInfo.add(loopPlayerName[1]);

		loopInfo.add(playerHits[0]);
		loopInfo.add(progressPanel);
		loopInfo.add(playerHits[1]);

		//fieldviews setup

		loopBoatsFieldView = new FieldPainterLoop[] { 
				new FieldPainterLoop(
						Setup.getPlayers()[0],
						notificationArea[0],
						winProgress,
						playerHits[1]),
				new FieldPainterLoop(
						Setup.getPlayers()[1],
						notificationArea[1],
						winProgress,
						playerHits[0])
		};

		for(int field = 0; field < loopBoatsFieldView.length; field++)
		{
			loopBoatsFieldView[field].setOtherField(loopBoatsFieldView[(field + 1) % 2]);
		}
		
		//disable first player's field (first player strikes second player's field)
		loopBoatsFieldView[0].setEnabled(false);
		
		fieldPanel[currentPlayer].add(
				loopBoatsFieldView[currentPlayer],
				BorderLayout.NORTH);
		
		
		fieldPanel[(currentPlayer + 1) % 2].add(
				loopBoatsFieldView[(currentPlayer + 1) % 2],
				BorderLayout.NORTH);
		
		this.add(loopInfo, BorderLayout.CENTER);
		
		this.pack();
		
		if (Setup.getPlayers()[currentPlayer]
		                       .equals(
		                    		   Loop.getLastTurn()) 
		                    		   && Loop.getLastTurn() != null)
		{
			currentPlayer = (currentPlayer + 1) % 2;
			loopBoatsFieldView[currentPlayer].switchFields();
		}
	}
	
	public void addHelpMenu()
	{
		help = new JMenu("help");
		help.setMnemonic(KeyEvent.VK_H);
		
		about = new JMenuItem("help");
		about.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				HelpMenu help = new HelpMenu("rules.html", "regels");
				help.init();
				
			}
		});
		
		rules = new JMenuItem("about");
		rules.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				HelpMenu about = new HelpMenu("about.html", "about");
				about.init();
			}
		});
		
		help.add(rules);
		help.add(about);
		
		menu.add(help);
	}

	public void updateBoard(boolean showall, Field field) {
		repaint();
		
	}
}
